﻿function model() {
    var codes = new Array();

    // 复制Model文件夹
    codes.push({
        type: 'copy',
        isfolder: true,
        source: '{0}\\Model'.format(set.VSVersion),
        target: 'Model'
    });

    // 逐表生成
    for (var i = 0; i < db.Selects.length; i++) {
        var table = db.Selects[i];
        var modelClassName = getModelClassName(table.Name);
        codes.push(tableInternalModel(table, modelClassName));
        codes.push(tableEditableModel(table, modelClassName));
    }

    return codes;
}

function tableEditableModel(table, modelClassName) {
    var NewLine = '\n';
    var temp = '';
    temp += 'using System;' + NewLine;
    temp += 'using System.Collections.Generic;' + NewLine;
    temp += 'using NHibernateHelper;' + NewLine;
    temp += 'using Newtonsoft.Json;' + NewLine;
    if (set.ModelStyle == 'MVC2') {
        temp += 'using System.ComponentModel;' + NewLine;
        temp += 'using System.ComponentModel.DataAnnotations;' + NewLine;
    }
    temp += NewLine;
    temp += 'namespace ' + getNamespace('Model') + NewLine;
    temp += '{' + NewLine;
    temp += '    /// <summary>' + NewLine;
    temp += '    /// 实体类 ' + table.Descn + NewLine;
    temp += '    /// </summary>' + NewLine;
    temp += '    public partial class {0}'.format(modelClassName) + NewLine;
    temp += '    { }' + NewLine;
    temp += '}';

    return {
        type: 'code',
        title: 'Model-editable',
        path: 'Model\\editable\\{0}.cs'.format(modelClassName),
        code: temp
    };
}

function tableInternalModel(table, modelClassName) {
    var idClassName = modelClassName + '_ID'; //数据表具有复合主键时的标识类的名称
    var allFields = table.Fields;
    var condFields = table.CondFields;
    var uncondFields = table.UncondFields;
    var hasCompositeKey = condFields.length > 1;//是否具有复合主键
    var NewLine = '\n';
    var temp = '';
    temp += 'using System;' + NewLine;
    temp += 'using NHibernateHelper;' + NewLine;
    temp += 'using Newtonsoft.Json;' + NewLine;
	temp += 'using System.ComponentModel;' + NewLine;
	temp += 'using System.ComponentModel.DataAnnotations;' + NewLine;
    temp += NewLine;
    temp += 'namespace {0}'.format(getNamespace('Model')) + NewLine;
    temp += '{' + NewLine;
    temp += '    /// <summary>' + NewLine;
    temp += '    /// 实体类 ' + table.Descn + ', 此类请勿动，以方便表字段更改时重新生成覆盖' + NewLine;
    temp += '    /// </summary>' + NewLine;
    temp += '    [Serializable]' + NewLine;
    temp += '    [ShouldMap]' + NewLine;
    temp += '    public partial class {0} : ICloneable'.format(modelClassName) + NewLine;
    temp += '    {' + NewLine;

    temp += '        public {0}()'.format(modelClassName) + NewLine;
    temp += '        { }' + NewLine;
    temp += '' + NewLine;
    temp += '        /// <summary>' + NewLine;
    temp += '        /// 构造函数 ' + table.Descn + NewLine;
    temp += '        /// </summary>' + NewLine;
    for (var i = 0; i < allFields.length; i++) {
        var field = allFields[i];
        temp += '        /// <param name="{0}">{1}</param>'.format(field.Name.toLowerCase(), field.Descn) + NewLine;
    }
    temp += '        public {0}({1}){2}'.format(modelClassName, getParms(), callAnotherCtorToCreateNewIDClassWhenHasCompositeKey()) + NewLine;

    function getParms() {
        var temp = '';
        for (var i = 0; i < allFields.length; i++) {
            var field = allFields[i];
            temp += '{0} {1}'.format(csType[field.DbType], field.Name.toLowerCase());
            if (i != allFields.length - 1)
                temp += ', ';
        }
        return temp;
    }

	function callAnotherCtorToCreateNewIDClassWhenHasCompositeKey(){
		if(hasCompositeKey)
		{
			var temp = ' : this(new {0}('.format(idClassName);
			for (var i = 0; i < condFields.length; i++) {
				var condField = condFields[i];
				temp += '{0}'.format(condField.Name.toLowerCase());
				if (i != condFields.length - 1)
					temp += ', ';
			}
			temp += ')'
			if(uncondFields.length > 0)
			{
				temp += ', ';
				for (var i = 0; i < uncondFields.length; i++) {
					var uncondField = uncondFields[i];
					temp += '{0}'.format(uncondField.Name.toLowerCase());
					if (i != uncondField.length - 1)
						temp += ', ';
				}
			}
			if(temp.endsWith(', ')){
				temp = temp.substr(0, temp.length - 2);
			}
			temp += ')';
			return temp;
		}
		else
		{
			return '';
		}
	}

    temp += '        {' + NewLine;
	if(!hasCompositeKey)
	{
	    for (var i = 0; i < allFields.length; i++) {
	        var field = allFields[i];
			//所有不是具有复合主键的数据表的主键的字段都存放在本类中
			temp += '            this.{0} = {1};'.format(field.Name, field.Name.toLowerCase()) + NewLine;
		}
	}
	
    temp += '        }' + NewLine;
    temp += NewLine;
	
	if(hasCompositeKey)
	{
		temp += '        /// <summary>' + NewLine;
		temp += '        /// 构造函数 ' + table.Descn + NewLine;
		temp += '        /// </summary>' + NewLine;
		for (var i = 0; i < allFields.length; i++) {
		    var field = allFields[i];
			temp += '        /// <param name="{0}">{1}</param>'.format(field.Name.toLowerCase(), field.Descn) + NewLine;
		}
		temp += '        public {0}({1}{2})'.format(modelClassName, getCompositeIDParm(), getUncondParms()) + NewLine;

		function getCompositeIDParm() {
			var temp = '';
			temp += '{0} {1}'.format(idClassName, idClassName.toLowerCase());
			if (uncondFields.length > 0)
				temp += ', ';
			return temp;
		}

		
		function getUncondParms() {
			var temp = '';
			for (var i = 0; i < uncondFields.length; i++) {
			    var uncondField = uncondFields[i];
			    temp += '{0} {1}'.format(csType[uncondField.DbType], uncondField.Name.toLowerCase());
				if (i != uncondFields.length - 1)
					temp += ', ';
			}
			if (temp.endsWith(', '))
			{
                temp = temp.substr(0, substr.length - ', '.length)
			}
			return temp;
		}

		temp += '        {' + NewLine;
		temp += '            this.{0} = {1};'.format(idClassName, idClassName.toLowerCase()) + NewLine;
		for (var i = 0; i < uncondFields.length; i++) {
		    var field = uncondFields[i];
			//所有不是主键的字段都存放在本类中
			temp += '            this.{0} = {1};'.format(field.Name, field.Name.toLowerCase()) + NewLine;
		}
		
		temp += '        }' + NewLine;
		temp += NewLine;
		
	}
	
	if(hasCompositeKey)
	{
		temp += '        #region 复合主键属性，这些属性都映射到{0}属性对应的标识对象中的同名属性'.format(idClassName) + NewLine;
		for (var i = 0; i < condFields.length; i++) {
		    var condField = condFields[i];
			temp += '        [Key]' + NewLine;
			temp += '        [ShouldNotMap] //具有复合主键的数据表中的主键字段不映射到数据模型类中的同名属性，而是映射到标识类中的同名属性' + NewLine;
			temp += '        public {0} {1}'.format(csType[condField.DbType], condField.Name) + NewLine;
			temp += '        {' + NewLine;
			temp += '            set {' + NewLine;
			temp += '                if({0} == null){'.format(idClassName, condField.Name) + NewLine;
			temp += '                    {0} = new {1}();'.format(idClassName, idClassName) + NewLine;
			temp += '                }' + NewLine;
			temp += '                {0}.{1} = value;'.format(idClassName, condField.Name) + NewLine;
			temp += '            }' + NewLine;
			temp += '            get {' + NewLine;
			temp += '                if({0} == null){'.format(idClassName, condField.Name) + NewLine;
			temp += '                    {0} = new {1}();'.format(idClassName, idClassName) + NewLine;
			temp += '                }' + NewLine;
			temp += '                return {0}.{1};'.format(idClassName, condField.Name) + NewLine;
			temp += '            }' + NewLine;
			temp += '        }' + NewLine;
			temp += NewLine;
		}
		temp += '        #endregion' + NewLine;
	}
    temp += NewLine;
    temp += '        #region 实体属性' + NewLine;
    temp += NewLine;
    if (set.ModelStyle == 'CS2') {
		if(hasCompositeKey)
		{
			//如果数据表具有复合主键，主键使用单独的类表示
			temp += '        private {0} _{1};'.format(idClassName, idClassName.toLowerCase()) + NewLine;
		}
		for (var i = 0; i < allFields.length; i++) {
			if(!hasCompositeKey || !field.IsCondField)
			{
				//不是复合主键，或者本字段不是主键，在类中使用字段存储属性值
			    var field = allFields[i];
				temp += '        private {0} _{1};'.format(csType[field.DbType], field.Name.toLowerCase()) + NewLine;
			}
        }
        temp += NewLine;
		if(hasCompositeKey)
		{
			
			//如果数据表具有复合主键，主键使用类型为标识类的一个属性表示，此属性不参与Json序列化
			temp += '        /// <summary>' + NewLine;
			temp += '        /// {0}的主键'.format(table.Name) + NewLine;
			temp += '        /// </summary>' + NewLine;
			temp += '        [Key]' + NewLine;
			temp += '        [JsonIgnore] //具有复合主键的数据表的数据模型类中的标识属性不参与Json序列化' + NewLine;
			temp += '        public virtual {0} {1}'.format(idClassName, idClassName) + NewLine;
			temp += '        {' + NewLine;
			temp += '            set { _{0} = value; }'.format(idClassName.toLowerCase()) + NewLine;
			temp += '            get { return _{0}; }'.format(idClassName.toLowerCase()) + NewLine;
			temp += '        }' + NewLine;
			temp += NewLine;
		}
        temp += NewLine;
        for (var i = 0; i < allFields.length; i++) {
            var field = allFields[i];
			if(!hasCompositeKey || !field.IsCondField)
			{
				//只要字段不是具有复合主键的数据表的主键字段，那么在类中都有对应的属性和字段
				temp += '        /// <summary>' + NewLine;
				temp += '        /// {0}'.format(field.Descn) + NewLine;
				temp += '        /// </summary>' + NewLine;
				temp += '        public virtual {0} {1}'.format(csType[field.DbType], field.Name) + NewLine;
				temp += '        {' + NewLine;
				temp += '            set { _{0} = value; }'.format(field.Name.toLowerCase()) + NewLine;
				temp += '            get { return _{0}; }'.format(field.Name.toLowerCase()) + NewLine;
				temp += '        }' + NewLine;
				temp += NewLine;
			}
        }
    } else {
		if(hasCompositeKey)
		{
			//如果数据表具有复合主键，主键使用类型为标识类的一个属性表示，此属性不参与Json序列化
			temp += '        /// <summary>' + NewLine;
			temp += '        /// {0}的主键'.format(table.Name) + NewLine;
			temp += '        /// </summary>' + NewLine;
			temp += '        [JsonIgnore]' + NewLine;
			temp += '        [Key]' + NewLine;
            temp += '        public virtual {0} {0} { get; set; }'.format(idClassName) + NewLine;
			temp += NewLine;
		}
		var fields = hasCompositeKey ? uncondFields : allFields;
        for (var i = 0; i < fields.length; i++) {
            var field = fields[i];
            temp += '        /// <summary>' + NewLine;
            temp += '        /// {0}'.format(field.Descn) + NewLine;
            temp += '        /// </summary>' + NewLine;
			if (field.IsCondField)
			{
				temp += '        [Key]' + NewLine;
			}
            if (set.ModelStyle == 'MVC2') {
                temp += '        [DisplayName("{0}")]'.format(field.Descn) + NewLine;
                if (!field.AllowNull)
                    temp += '        [Required(ErrorMessage="{0}不能为空。")]'.format(field.Descn) + NewLine;
                if (csMethod[field.DbType] == 'GetString'){
					temp += '        [StringLength({0}, MinimumLength = 1, ErrorMessage = "{1}为1-{0}位。")]'.format(field.Length, field.Descn) + NewLine;
				}
            }
            temp += '        public virtual {0} {1} { get; set; }'.format(csType[field.DbType], field.Name) + NewLine;
            temp += NewLine;
        }
    }
    temp += '        #endregion' + NewLine;
    temp += NewLine;
    temp += '        #region ICloneable 成员' + NewLine;
    temp += NewLine;
    temp += '        public virtual object Clone()' + NewLine;
    temp += '        {' + NewLine;
    temp += '            return this.MemberwiseClone();' + NewLine;
    temp += '        }' + NewLine;
    temp += NewLine;
    temp += '        #endregion' + NewLine;
    temp += NewLine;
    temp += '        public override bool Equals(object obj)' + NewLine;
    temp += '        {' + NewLine;
    temp += '            {0} model = obj as {0};'.format(modelClassName) + NewLine;
    temp += '            return model != null && model.{0} == this.{0};'.format(hasCompositeKey ? idClassName : condFields[0].Name) + NewLine;
    temp += '        }' + NewLine;
    temp += NewLine;
    temp += '        public override int GetHashCode()' + NewLine;
    temp += '        {' + NewLine;
	temp += '            return {0}.GetHashCode();'.format(hasCompositeKey ? idClassName : condFields[0].Name) + NewLine;
    temp += '        }' + NewLine;
    temp += '    }' + NewLine;
	if(hasCompositeKey)
	{
		//数据表具有复合主键时的标识类
		temp += NewLine;
		temp += '    /// <summary>' + NewLine;
		temp += '    /// 实体类 ' + table.Descn + ' 的标识类, 此类请勿动，以方便表字段更改时重新生成覆盖' + NewLine;
		temp += '    /// </summary>' + NewLine;
		temp += '    [Serializable]' + NewLine;
		temp += '    [ShouldMap]' + NewLine;
		temp += '    [Component]' + NewLine;
		temp += '    public partial class {0} : ICloneable, IEquatable<{0}>'.format(idClassName) + NewLine;
		temp += '    {' + NewLine;
		temp += '        public {0}()'.format(idClassName) + NewLine;
		temp += '        { }' + NewLine;
		temp += '' + NewLine;
		temp += '        /// <summary>' + NewLine;
		temp += '        /// 构造函数 ' + table.Descn + NewLine;
		temp += '        /// </summary>' + NewLine;
		for (var i = 0; i < allFields.length; i++) {
		    var field = allFields[i];
			temp += '        /// <param name="{0}">{1}</param>'.format(field.Name.toLowerCase(), field.Descn) + NewLine;
		}
		temp += '        public {0}({1})'.format(idClassName, getCondParms()) + NewLine;

		function getCondParms() {
			var temp = '';
			for (var i = 0; i < condFields.length; i++) {
				var field = condFields[i];
				temp += '{0} {1}'.format(csType[field.DbType], field.Name.toLowerCase());
				if (i != condFields.length - 1)
					temp += ', ';
			}
			return temp;
		}

		temp += '        {' + NewLine;
		for (var i = 0; i < condFields.length; i++) {
			var field = condFields[i];
			temp += '            this.{0} = {1};'.format(field.Name, field.Name.toLowerCase()) + NewLine;
		}
		temp += '        }' + NewLine;
		temp += '        #region 实体属性' + NewLine;
		temp += NewLine;
		if (set.ModelStyle == 'CS2') {
			for (var i = 0; i < condFields.length; i++) {
				var field = condFields[i];
				temp += '        private {0} _{1};'.format(csType[field.DbType], field.Name.toLowerCase()) + NewLine;
			}
			temp += NewLine;
			for (var i = 0; i < condFields.length; i++) {
				var field = condFields[i];
				temp += '        /// <summary>' + NewLine;
				temp += '        /// {0}'.format(field.Descn) + NewLine;
				temp += '        /// </summary>' + NewLine;
				temp += '        public {0} {1}'.format(csType[field.DbType], field.Name) + NewLine;
				temp += '        {' + NewLine;
				temp += '            set { _{0} = value; }'.format(field.Name.toLowerCase()) + NewLine;
				temp += '            get { return _{0}; }'.format(field.Name.toLowerCase()) + NewLine;
				temp += '        }' + NewLine;
				temp += NewLine;
			}
		} else {
			for (var i = 0; i < condFields.length; i++) {
				var field = condFields[i];
				temp += '        /// <summary>' + NewLine;
				temp += '        /// {0}'.format(field.Descn) + NewLine;
				temp += '        /// </summary>' + NewLine;
				if (set.ModelStyle == 'MVC2') {
					temp += '        [DisplayName("{0}")]'.format(field.Descn) + NewLine;
					if (!field.AllowNull)
						temp += '        [Required(ErrorMessage="{0}不能为空。")]'.format(field.Descn) + NewLine;
					if (csMethod[field.DbType] == 'GetString'){
						temp += '        [StringLength({0}, MinimumLength = 1, ErrorMessage = "{1}为1-{0}位。")]'.format(field.Length, field.Descn) + NewLine;
					}
				}
				temp += '        public virtual {0} {1} { get; set; }'.format(csType[field.DbType], field.Name) + NewLine;
				temp += NewLine;
			}
		}
		temp += '        #endregion' + NewLine;

		temp += NewLine;
		temp += '        #region ICloneable 成员' + NewLine;
		temp += NewLine;
		temp += '        public object Clone()' + NewLine;
		temp += '        {' + NewLine;
		temp += '            return this.MemberwiseClone();' + NewLine;
		temp += '        }' + NewLine;
		temp += NewLine;
		temp += '        #endregion' + NewLine;
		temp += NewLine;
		temp += '        public override bool Equals(object obj)' + NewLine;
		temp += '        {' + NewLine;
		temp += '            return Equals(obj as {0});'.format(modelClassName) + NewLine;


		temp += '                return true;' + NewLine;
		temp += '' + NewLine;
		temp += '            return false;' + NewLine;
		temp += '        }' + NewLine;

		temp += NewLine;
		temp += '        public bool Equals({0} model)'.format(idClassName) + NewLine;
		temp += '        {' + NewLine;
		temp += '            return {0};'.format(getCompareOfIdClass()) + NewLine;

		function getCompareOfIdClass() {
			var temp = new Array();
			temp.push('model != null');
			for (var i = 0; i < condFields.length; i++) {
				var field = condFields[i];
				temp.push('model.{0} == this.{0}'.format(field.Name));
			}
			return temp.join(' && ');
		}
		temp += '        }' + NewLine;
		temp += '' + NewLine;
		temp += '        public override int GetHashCode()' + NewLine;
		temp += '        {' + NewLine;
		temp += '            int hash = GetType().GetHashCode();' + NewLine;
		for (var i = 0; i < condFields.length; i++) {
			var field = condFields[i];
			temp += '            hash = (hash * 397) ^ {0}.GetHashCode();'.format(field.Name) + NewLine;
		}
		temp += '' + NewLine;
		temp += '            return hash;' + NewLine;
		temp += '        }' + NewLine;
		temp += '    }' + NewLine;
	}
    temp += '}';


    return {
        type: 'code',
        title: 'Model-internal',
        path: 'Model\\internal\\{0}.cs'.format(modelClassName),
        code: temp
    };
}
